"""
Django默认使用用户名去认证用户的,
所以我们要想实现多账号登录(用户名或者手机号),
自定义用户认证.(笨方法)和查看底层代码(聪明的方法)


自定义用户认证后端步骤:
    在 users 应用中新建 utils.py 文件
    新建类，继承自 ModelBackend
    重写认证 authenticate( ) 方法
    分别使用用户名和手机号查询用户
    返回查询到的用户实例
"""
# # 导入:
# from django.contrib.auth.backends import ModelBackend
# import re
# from .models import User
#
# def get_user_by_account(account):
#     '''判断 account 是否是手机号, 返回 user 对象'''
#     try:
#         if re.match('^1[3-9]\d{9}$', account):
#             # account 是手机号
#             # 根据手机号从数据库获取 user 对象返回.
#             user = User.objects.get(mobile=account)
#         else:
#             # account 是用户名
#             # 根据用户名从数据库获取 user 对象返回.
#             user = User.objects.get(username=account)
#     except User.DoesNotExist:
#         # 如果 account 既不是用户名也不是手机号
#         # 我们返回 None
#         return None
#     else:
#         # 如果得到 user, 则返回 user
#         return user
#
# # 继承自 ModelBackend, 重写 authenticate 函数
# class UsernameMobileAuthBackend(ModelBackend):
#     """自定义用户认证后端"""
#
#     def authenticate(self, request, username=None, password=None, **kwargs):
#         """
#         重写认证方法，实现用户名和mobile登录功能
#         :param request: 请求对象
#         :param username: 用户名
#         :param password: 密码
#         :param kwargs: 其他参数
#         :return: user
#         """
#
#         # 自定义验证用户是否存在的函数:
#         # 根据传入的 username 获取 user 对象
#         # username 可以是手机号也可以是账号
#         user = get_user_by_account(username)
#
#         # 校验 user 是否存在并校验密码是否正确
#         if user and user.check_password(password):
#             # 如果user存在, 密码正确, 则返回 user
#             return user


# 然后settings.py中配置自定义选项,使用我们的认证方式
# 指定自定义的用户认证后端:
# AUTHENTICATION_BACKENDS = ['users.utils.UsernameMobileAuthBackend']


# 定义生成邮箱验证链接方法
from itsdangerous import TimedJSONWebSignatureSerializer as Serializer, BadData
from django.conf import settings
from apps.users.models import User


def generate_email_verify_url(user):
    """
    生成邮箱验证激活链接
    :param user: 当前要添加验证邮箱的登录用户
    :return: 邮箱激活链接
    """
    # 创建序列化器对象
    s = Serializer(settings.SECRET_KEY, 3600*24)

    # 准备序列化的数据(拼接参数)
    data = {'user_id': user.id, 'email': user.email}

    # 序列化
    # 加密生成 token 值,这个值是 bytes 类型,所以解码为 str
    token = s.dumps(data).decode()

    # 邮箱激活链接(拼接url)
    # verify_url = 'http://www.meiduo.site:8080/success_verify_email.html?token='
    verify_url = settings.EMAIL_VERIFY_URL + token

    # 返回
    return verify_url


def check_email_verify_token(token):
    """
    反序列化用户信息密文(解密)
    :param token: 用户信息密文
    :return: 用户信息
    """
    # 创建序列化器对象
    s = Serializer(settings.SECRET_KEY, 3600 * 24)

    # 反序列化
    try:
        # 解析传入的 token 值, 获取数据 data
        data = s.loads(token)
    except BadData:
        # 如果传入的 token 中没有值,则报错
        return None
    else:
        # 如果有值, 则提取用户信息
        user_id = data.get('user_id')
        email = data.get('email')

    try:
        # 使用user_id 和 email查询对应的用户对象
        user = User.objects.get(id=user_id,
                                email=email)
    except User.DoesNotExist:
        # 如果用户不存在, 则返回 None
        return None
    else:
        # 如果存在则直接返回
        return user
